
#include <stdint.h>
#include <string.h>

#include "CardExchangeApdu.h"

int Card_SelectAID(uint8_t card, const uint8_t* aid, uint8_t len){
	uint8_t cmd[64] = {0x00, 0xA4, 0x04, 0x00, len,};
	if(len > (64 - 5)){
		return -1;
	}
	memcpy(&cmd[5], aid, len);
	return Card_ExchangeApdu(card, cmd, len + 5, 0, 0);
}

int Card_SelectFileById(uint8_t card, uint16_t fid){
	uint8_t cmd[]
		= {	0x00, 0xA4, 0x00, 0x00, 0x02, 
			(uint8_t)(fid >> 8), (uint8_t)(fid & 0xFF)};

	return Card_ExchangeApdu(card, cmd, sizeof(cmd), 0, 0);
}


int Card_GetChallenge(uint8_t card, uint8_t clen, uint8_t random[]){
	uint8_t cmd[] = {0x00, 0x84, 0x00, 0x00, clen};
	
	if(clen > 8){
		return -1;
	}
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), random, 0);
}

int Card_Verify(uint8_t card, uint8_t pin[], uint8_t len){
	uint8_t cmd [32] = {0x00, 0x20, 0x00, 0x00, len,};
	memcpy(cmd+5, pin, len);
	return Card_ExchangeApdu(card, cmd, len + 5, 0, 0);
}

int Card_RawExternalAuth(uint8_t card, uint8_t keyId, uint8_t random[], uint8_t rlen){
	uint8_t auth[32] = {0x00, 0x82, 0x00, keyId, rlen,};
	memcpy(auth + 5, random, rlen);
	return Card_ExchangeApdu(card, auth, rlen + 5, 0, 0);
}


int Card_RawInternalAuth(uint8_t card, uint8_t keyId, uint8_t authData[], uint8_t len, uint8_t resp[], uint16_t*rlen){
	uint8_t auth[32] = {0x00, 0x88, 0x00, keyId, len,};
	
	memcpy(auth + 5, authData, len);
	return Card_ExchangeApdu(card, auth, len + 5, resp, rlen);
}


int Card_ReadBinaryShortId(uint8_t card, uint8_t fid, uint8_t offset, uint8_t buf[], uint8_t len){
	uint8_t cmd[] = {0x00, 0xB0, fid, offset, len};
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), buf, 0);
}


int Card_ReadBinary0(uint8_t card, uint16_t offset, uint8_t buf[], uint8_t len){
	uint8_t cmd[] = {0x00, 0xB0, (uint8_t)(offset >> 8), (uint8_t)(offset & 0xFF), len};
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), buf, 0);
}

int Card_UpdateBinary0(uint8_t card, uint16_t offset, uint8_t buf[], uint8_t len){
	uint8_t cmd[260] = {0x00, 0xD6, (uint8_t)(offset >> 8), (uint8_t)(offset & 0xFF), len, };
#if 0
	if(len > (sizeof(cmd) - 5)){
		return -1;
	}
#endif 
	memcpy(cmd + 5, buf, len);
	return Card_ExchangeApdu(card, cmd, len + 5, buf, 0);
}


int Card_ReadBinaryFile0(uint8_t card, uint16_t fid, uint16_t offset, uint8_t buf[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_ReadBinary0(card, offset, buf, len);

}

int Card_WriteBinaryFile0(uint8_t card, uint16_t fid, uint16_t offset, uint8_t buf[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_UpdateBinary0(card, offset, buf, len);
}


int Card_ReadBinary(uint8_t card, uint16_t offset, uint8_t buf[], uint8_t len){
	uint8_t cmd[] = {0x00, 0x42, (uint8_t)(offset >> 8), (uint8_t)(offset & 0xFF), len};
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), buf, 0);
}

int Card_ReadRecord(uint8_t card, uint8_t rid, uint8_t record[], uint8_t len){
	uint8_t cmd[] = {0x00, 0xB2, rid, 0x04, len};
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), record, 0);
}

int Card_UpdateBinary(uint8_t card, uint16_t offset, uint8_t buf[], uint8_t len){
	uint8_t cmd[64] = {0x00, 0x41, (uint8_t)(offset >> 8), (uint8_t)(offset & 0xFF), len, };
	if(len > (sizeof(cmd) - 5)){
		return -1;
	}
	memcpy(cmd + 5, buf, len);
	return Card_ExchangeApdu(card, cmd, len + 5, buf, 0);
}

int Card_UpdateRecord(uint8_t card, uint8_t rid, uint8_t p2, uint8_t record[], uint8_t len){
	
	uint8_t cmd[64] = { 0x00, 0xDC, rid, p2, len};
	if(len > (sizeof(cmd) - 5)){
		return -1;
	}
	memcpy(cmd + 5, record, len);
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), 0, 0);
}


int Card_AppendRecord(uint8_t card, uint8_t sid, uint8_t record[], uint8_t len){
	uint8_t cmd[64] = {0x00, 0xE2, 0x00, sid, len};
	if(len > (sizeof(cmd) - 5)){
		return -1;
	}
	memcpy(cmd + 5, record, len);
	return Card_ExchangeApdu(card, cmd, sizeof(cmd), 0, 0);
}


int Card_ReadBinaryFile(uint8_t card, uint16_t fid, uint16_t offset, uint8_t buf[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_ReadBinary(card, offset, buf, len);

}

int Card_WriteBinaryFile(uint8_t card, uint16_t fid, uint16_t offset, uint8_t buf[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_UpdateBinary(card, offset, buf, len);
}


int Card_ReadRecordFile(uint8_t card, uint16_t fid, uint8_t rid, uint8_t record[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_ReadRecord(card, rid, record, len);
}

int Card_WriteRecordFile(uint8_t card, uint16_t fid, uint8_t record[], uint8_t len){
	int ret;	
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	return Card_UpdateRecord(card, 0x00, 0x03, record, len);
}

int Card_AppendRecordFile(uint8_t card, uint16_t fid, uint8_t record[], uint8_t len){
	int ret;
	ret = Card_SelectFileById(card, fid);
	if(ret){
		return ret;
	}
	
	return Card_AppendRecord(card, 0x04, record, len);
}



#if 0
int TestCardCmd(void){
	int ret;
	uint8_t random[8];
	uint8_t customerKey[16];
	uint8_t rlen;

	ret = Card_SelectFileById(0x3F00);
	memset(customerKey, 0xFF, sizeof(customerKey));	
	memset(random, 0, sizeof(random));
#if 1
	ret = Card_GetChallenge(4, random);
	if(ret){
		return ret;
	}
#else
	unsigned char testResp[6] = {0xDD, 0xB8, 0xE1, 0xB3, 0x90, 0x00 };
	memcpy(random, testResp, 4);
#endif 
	ret = Card_ExternalAuth(0x00, customerKey, sizeof(customerKey), random, 8);
	return ret;
}
#endif 


